home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume20 / deliver2.0 / part03 < prev    next >
Encoding:
Internet Message Format  |  1989-10-15  |  34.6 KB

  1. Subject:  v20i025:  Deliver, flexible email delivery system, Part03/04
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Chip Salzenberg <chip@ateng.com>
  7. Posting-number: Volume 20, Issue 25
  8. Archive-name: deliver2.0/part03
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of shell archive."
  17. # Contents:  debug.c dest.c dfile.c lock.c main.c
  18. # Wrapped by network@ateng on Fri Jun  9 13:21:01 1989
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'debug.c' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'debug.c'\"
  22. else
  23. echo shar: Extracting \"'debug.c'\" \(1063 characters\)
  24. sed "s/^X//" >'debug.c' <<'END_OF_FILE'
  25. X/* $Header: debug.c,v 2.1 89/06/09 12:25:17 network Exp $
  26. X *
  27. X * Debugging output.
  28. X *
  29. X * $Log:    debug.c,v $
  30. X * Revision 2.1  89/06/09  12:25:17  network
  31. X * Update RCS revisions.
  32. X * 
  33. X * Revision 1.4  89/06/09  12:23:42  network
  34. X * Baseline for 2.0 release.
  35. X * 
  36. X */
  37. X
  38. X#include "deliver.h"
  39. X
  40. X/*----------------------------------------------------------------------
  41. X * Print out a complete dump of all destinations
  42. X */
  43. X
  44. Xdumpdests(when)
  45. Xchar    *when;
  46. X{
  47. X    DEST    *d;
  48. X
  49. X    message("Destinations %s:\n", when);
  50. X    for (d = first_dest(); d; d = next_dest(d))
  51. X    {
  52. X        message("\t%s", d->d_name);
  53. X
  54. X        switch (d->d_class)
  55. X        {
  56. X        case CL_USER:
  57. X            /* it's understood */
  58. X            break;
  59. X        case CL_MBOX:
  60. X            message(", mailbox='%s'", d->d_mailbox);
  61. X            break;
  62. X        case CL_UUCP:
  63. X            message(" (UUCP)");
  64. X            break;
  65. X        }
  66. X        message("; ");
  67. X        switch (d->d_state)
  68. X        {
  69. X        case ST_WORKING:
  70. X            message("Working");
  71. X            break;
  72. X        case ST_HOLD:
  73. X            message("Hold");
  74. X            break;
  75. X        case ST_DONE:
  76. X            message("Done");
  77. X            break;
  78. X        case ST_ERROR:
  79. X            message("Error (%s)", derrmsg(d->d_error));
  80. X            break;
  81. X        }
  82. X        message("\n");
  83. X    }
  84. X}
  85. END_OF_FILE
  86. if test 1063 -ne `wc -c <'debug.c'`; then
  87.     echo shar: \"'debug.c'\" unpacked with wrong size!
  88. fi
  89. # end of 'debug.c'
  90. fi
  91. if test -f 'dest.c' -a "${1}" != "-c" ; then 
  92.   echo shar: Will not clobber existing file \"'dest.c'\"
  93. else
  94. echo shar: Extracting \"'dest.c'\" \(2938 characters\)
  95. sed "s/^X//" >'dest.c' <<'END_OF_FILE'
  96. X/* $Header: dest.c,v 2.1 89/06/09 12:25:22 network Exp $
  97. X *
  98. X * Operations on the list of mail destinations.
  99. X *
  100. X * $Log:    dest.c,v $
  101. X * Revision 2.1  89/06/09  12:25:22  network
  102. X * Update RCS revisions.
  103. X * 
  104. X * Revision 1.5  89/06/09  12:23:45  network
  105. X * Baseline for 2.0 release.
  106. X * 
  107. X */
  108. X
  109. X#include "deliver.h"
  110. X
  111. X/*
  112. X * Local data.
  113. X */
  114. X
  115. Xstatic  DEST    deadhead = { &deadhead, &deadhead };
  116. X#define HEADPTR    (&deadhead)
  117. X
  118. X/*----------------------------------------------------------------------
  119. X * Add a new destination to the list (unless it already exists).
  120. X * Return pointer to DEST.
  121. X */
  122. X
  123. XDEST *
  124. Xdest(name, mailbox)
  125. Xchar    *name;
  126. Xchar    *mailbox;
  127. X{
  128. X    DEST    *d;
  129. X    DCLASS   class;
  130. X
  131. X    if (strchr(name, '!'))
  132. X        class = CL_UUCP;
  133. X    else if (mailbox)
  134. X        class = CL_MBOX;
  135. X    else
  136. X        class = CL_USER;
  137. X
  138. X    for (d = HEADPTR->d_next; d != HEADPTR; d = d->d_next)
  139. X    {
  140. X        if (d->d_class != class)
  141. X            continue;
  142. X
  143. X        if (strcmp(d->d_name, name) != 0)
  144. X            continue;
  145. X
  146. X        /*
  147. X         * If this destination has a named mailbox, then
  148. X         * test it for equality as well.
  149. X         */
  150. X
  151. X        if (class == CL_MBOX
  152. X         && strcmp(d->d_mailbox, mailbox) != 0)
  153. X            continue;
  154. X
  155. X        /*
  156. X         * Like, gnarly, dude!  It's already in the chain!
  157. X         */
  158. X
  159. X        return d;
  160. X    }
  161. X
  162. X    /*
  163. X     * The given dest isn't in the list, so we have to add it.
  164. X     */
  165. X
  166. X    d = (DEST *) zalloc(sizeof(DEST));
  167. X    d->d_class = class;
  168. X    d->d_state = ST_WORKING;
  169. X    d->d_name = copystr(name);
  170. X    if (class == CL_MBOX)
  171. X        d->d_mailbox = copystr(mailbox);
  172. X
  173. X    /*
  174. X     * Check address for validity.
  175. X     */
  176. X
  177. X    if (!valid_address(name))
  178. X        dest_err(d, E_IVADDR);
  179. X    else if (class != CL_UUCP && name_context(name) == NULL)
  180. X        dest_err(d, E_NSUSER);
  181. X
  182. X    /*
  183. X     * Put new address at the end of of the chain.
  184. X     * (This is important!  Other code depends on it.)
  185. X     */
  186. X
  187. X    d->d_prev = HEADPTR->d_prev;
  188. X    d->d_next = HEADPTR;
  189. X    d->d_prev->d_next = d;
  190. X    d->d_next->d_prev = d;
  191. X
  192. X    return d;
  193. X}
  194. X
  195. X/*----------------------------------------------------------------------
  196. X * Return pointer to first DEST in the list.
  197. X */
  198. X
  199. XDEST *
  200. Xfirst_dest()
  201. X{
  202. X    if (HEADPTR->d_next != HEADPTR)
  203. X        return HEADPTR->d_next;
  204. X
  205. X    return NULL;
  206. X}
  207. X
  208. X/*----------------------------------------------------------------------
  209. X * Return pointer to next DEST in the list, or NULL.
  210. X */
  211. X
  212. XDEST *
  213. Xnext_dest(d)
  214. XDEST    *d;
  215. X{
  216. X    if (d && (d = d->d_next) != HEADPTR)
  217. X        return d;
  218. X
  219. X    return NULL;
  220. X}
  221. X
  222. X/*----------------------------------------------------------------------
  223. X * Return an error message given a DERROR.
  224. X */
  225. X
  226. Xchar *
  227. Xderrmsg(e)
  228. XDERROR  e;
  229. X{
  230. X    static  char    unknown_buf[40];
  231. X
  232. X    switch (e)
  233. X    {
  234. X    case E_IVADDR:
  235. X        return "Invalid address string";
  236. X    case E_NSUSER:
  237. X        return "No such user";
  238. X    case E_NSHOST:
  239. X        return "No such host (UUCP addresses)";
  240. X    case E_CTPERM:
  241. X        return "No permissions for that context";
  242. X    case E_CTLOST:
  243. X        return "Context lost (should never happen)";
  244. X    case E_MBOX:
  245. X        return "Can't write to mailbox";
  246. X    case E_UUX:
  247. X        return "Can't pipe to uux";
  248. X    }
  249. X
  250. X    (void) sprintf(unknown_buf, "Unknown error %d", e);
  251. X    return unknown_buf;
  252. X}
  253. END_OF_FILE
  254. if test 2938 -ne `wc -c <'dest.c'`; then
  255.     echo shar: \"'dest.c'\" unpacked with wrong size!
  256. fi
  257. # end of 'dest.c'
  258. fi
  259. if test -f 'dfile.c' -a "${1}" != "-c" ; then 
  260.   echo shar: Will not clobber existing file \"'dfile.c'\"
  261. else
  262. echo shar: Extracting \"'dfile.c'\" \(8068 characters\)
  263. sed "s/^X//" >'dfile.c' <<'END_OF_FILE'
  264. X/* $Header: dfile.c,v 2.1 89/06/09 12:25:24 network Exp $
  265. X *
  266. X * Filter destination(s) through delivery file(s).
  267. X *
  268. X * $Log:    dfile.c,v $
  269. X * Revision 2.1  89/06/09  12:25:24  network
  270. X * Update RCS revisions.
  271. X * 
  272. X * Revision 1.10  89/06/09  12:23:49  network
  273. X * Baseline for 2.0 release.
  274. X * 
  275. X */
  276. X
  277. X#include "deliver.h"
  278. X#include <sys/stat.h>
  279. X
  280. X/*----------------------------------------------------------------------
  281. X * Filter all valid destinations through the global delivery file.
  282. X */
  283. X
  284. Xsys_dfile(dac, dav)
  285. Xint     dac;
  286. Xchar    **dav;
  287. X{
  288. X    char    **fav;
  289. X    int     fac, a;
  290. X    struct stat st;
  291. X
  292. X    /*
  293. X     * If there is no global delivery file, forget it.
  294. X     */
  295. X
  296. X    if (stat(sys_deliver, &st) == -1)
  297. X    {
  298. X        if (verbose)
  299. X            message("no system delivery file\n");
  300. X        return -1;
  301. X    }
  302. X
  303. X    /*
  304. X     * If we've been asked not to run delivery files, forget it.
  305. X     */
  306. X
  307. X    if (!rundfiles)
  308. X    {
  309. X        if (verbose)
  310. X            message("system delivery file disabled\n");
  311. X        return -1;
  312. X    }
  313. X
  314. X    /*
  315. X     * Collect the arguments for the delivery file.
  316. X     */
  317. X
  318. X    fav = (char **) zalloc((dac + 3) * sizeof(char **));
  319. X    fav[0] = shell;
  320. X    fav[1] = sys_deliver;
  321. X    fac = 2;
  322. X
  323. X    for (a = 0; a < dac; ++a)
  324. X    {
  325. X        char    *addr;
  326. X
  327. X        addr = dav[a];
  328. X        if (valid_address(addr))
  329. X        {
  330. X            /* Let the delivery file handle valid addresses. */
  331. X
  332. X            fav[fac++] = addr;
  333. X        }
  334. X        else
  335. X        {
  336. X            /* Note invalid address(es); report them later. */
  337. X
  338. X            (void) dest(addr, (char *) NULL);
  339. X        }
  340. X    }
  341. X
  342. X    fav[fac] = NULL;
  343. X
  344. X    /*
  345. X     * If there were any good names found, let loose the delivery
  346. X     * file.  Note the meaning of "good" is "well-formed", not "valid".
  347. X     * Thus the system delivery file has control over the handling of
  348. X     * all local deliveries, not just those to valid users.
  349. X     */
  350. X
  351. X    if (fac > 2)
  352. X        (void) do_dfile(eff_ct, fav, (DEST *)NULL);
  353. X
  354. X    free((char *) fav);
  355. X
  356. X    return 0;
  357. X}
  358. X
  359. X/*----------------------------------------------------------------------
  360. X * Filter some undelivered destinations through the post-user
  361. X * delivery file.
  362. X */
  363. X
  364. Xpost_dfile()
  365. X{
  366. X    DEST    *d;
  367. X    char    **fav;
  368. X    int     num_dests, fac;
  369. X    struct stat st;
  370. X
  371. X    /*
  372. X     * If there is no post-user delivery file, forget it.
  373. X     */
  374. X
  375. X    if (stat(post_deliver, &st) == -1)
  376. X    {
  377. X        if (verbose)
  378. X            message("no post-user delivery file\n");
  379. X        return -1;
  380. X    }
  381. X
  382. X    /*
  383. X     * If we've been asked not to run delivery files, forget it.
  384. X     */
  385. X
  386. X    if (!rundfiles)
  387. X    {
  388. X        if (verbose)
  389. X            message("post-user delivery file disabled\n");
  390. X        return -1;
  391. X    }
  392. X
  393. X    /*
  394. X     * Generate the delivery file argument list.
  395. X     */
  396. X
  397. X    num_dests = 0;
  398. X    for (d = first_dest(); d; d = next_dest(d))
  399. X        ++num_dests;
  400. X
  401. X    fav = (char **) zalloc((num_dests + 3) * sizeof(char **));
  402. X    fav[0] = shell;
  403. X    fav[1] = post_deliver;
  404. X    fac = 2;
  405. X
  406. X    for (d = first_dest(); d; d = next_dest(d))
  407. X    {
  408. X        if ((d->d_class == CL_USER || d->d_class == CL_UUCP)
  409. X         && (d->d_state == ST_WORKING
  410. X          || (d->d_state == ST_ERROR && d->d_error == E_NSUSER)))
  411. X        {
  412. X            fav[fac++] = d->d_name;
  413. X            d->d_state = ST_HOLD;
  414. X        }
  415. X    }
  416. X
  417. X    fav[fac] = NULL;
  418. X
  419. X    if (fac > 2)
  420. X        (void) do_dfile(eff_ct, fav, (DEST *)NULL);
  421. X
  422. X    free((char *) fav);
  423. X
  424. X    return 0;
  425. X}
  426. X
  427. X/*----------------------------------------------------------------------
  428. X * Filter all user destinations through their local delivery files.
  429. X */
  430. X
  431. Xuser_dfiles()
  432. X{
  433. X    DEST    *d;
  434. X    int     nfound;
  435. X
  436. X    /*
  437. X     * If we've been asked not to run delivery files, forget it.
  438. X     */
  439. X
  440. X    if (!rundfiles)
  441. X    {
  442. X        if (verbose)
  443. X            message("user delivery files disabled\n");
  444. X
  445. X        return -1;
  446. X    }
  447. X
  448. X
  449. X    /*
  450. X     * Continue to loop through all addresses until no destination
  451. X     * that needs expanding can be found.
  452. X     */
  453. X
  454. X    do {
  455. X        nfound = 0;
  456. X        for (d = first_dest(); d; d = next_dest(d))
  457. X        {
  458. X            if (d->d_class == CL_USER
  459. X             && d->d_state == ST_WORKING
  460. X             && !d->d_dfdone)
  461. X            {
  462. X                one_dfile(d);
  463. X                d->d_dfdone = TRUE;
  464. X            }
  465. X        }
  466. X    } while (nfound > 0);
  467. X
  468. X    return 0;
  469. X}
  470. X
  471. X/*----------------------------------------------------------------------
  472. X * Run the delivery file (if any) for the specified destination.
  473. X */
  474. X
  475. Xone_dfile(d)
  476. XDEST    *d;
  477. X{
  478. X    CONTEXT *ct;
  479. X    char    *fav[4];
  480. X    char    udel_path[100];
  481. X    struct stat st;
  482. X
  483. X    if ((ct = name_context(d->d_name)) == NULL)
  484. X    {
  485. X        dest_err(d, E_CTLOST);
  486. X        return;
  487. X    }
  488. X
  489. X    /*
  490. X     * If user's home directory is missing, forget it.
  491. X     * If user's home directory is writable to the world,
  492. X     * executing the delivery file would allow a security breach!
  493. X     * Thanks to Jon Zeeff for this hint...
  494. X     */
  495. X
  496. X    if (stat(ct->ct_home, &st) == -1
  497. X     || (st.st_mode & S_IFMT) != S_IFDIR)
  498. X    {
  499. X        if (verbose)
  500. X            message("user %s: home directory %s is missing!\n",
  501. X                ct->ct_name, ct->ct_home);
  502. X        return;
  503. X    }
  504. X
  505. X    if (st.st_mode & 02)
  506. X    {
  507. X        if (verbose)
  508. X            message("user %s: home directory is writable to the world!\n",
  509. X                ct->ct_name);
  510. X        return;
  511. X    }
  512. X
  513. X    /*
  514. X     * If there is no delivery file to execute, just return.
  515. X     */
  516. X
  517. X    (void) sprintf(udel_path, "%s/%s", ct->ct_home, user_deliver);
  518. X    if (stat(udel_path, &st) == -1)
  519. X    {
  520. X        if (verbose)
  521. X            message("%s has no delivery file\n", d->d_name);
  522. X        return;
  523. X    }
  524. X
  525. X    /*
  526. X     * Time to run the file!
  527. X     * We put this dest on hold, so that it will be ignored unless
  528. X     * the delivery file names it.
  529. X     */
  530. X
  531. X    d->d_state = ST_HOLD;
  532. X
  533. X    fav[0] = shell;
  534. X    fav[1] = udel_path;
  535. X    fav[2] = d->d_name;
  536. X    fav[3] = NULL;
  537. X    (void) do_dfile(ct, fav, d);
  538. X}
  539. X
  540. X/*----------------------------------------------------------------------
  541. X * Process a delivery file.
  542. X */
  543. X
  544. Xint
  545. Xdo_dfile(ct, av, d)
  546. XCONTEXT *ct;
  547. Xchar    **av;
  548. XDEST    *d;
  549. X{
  550. X    FILE    *fp;
  551. X    char    *name, *mailbox;
  552. X
  553. X    if (!ct)
  554. X        return -1;
  555. X
  556. X    if (! ok_context(ct))
  557. X    {
  558. X        if (d)
  559. X            dest_err(d, E_CTPERM);
  560. X        else
  561. X            message("No permissions to run as %s\n", ct->ct_name);
  562. X
  563. X        return -1;
  564. X    }
  565. X
  566. X    /* Copy the temp files again */
  567. X
  568. X    if (copy_again() < 0)
  569. X        return -1;
  570. X
  571. X    /* Allow the given user to own and read the copies */
  572. X
  573. X    if (give_temps(ct) < 0)
  574. X        return -1;
  575. X
  576. X    /* Here we go! */
  577. X
  578. X    if (verbose)
  579. X        message("Processing delivery file as %s\n", ct->ct_name);
  580. X
  581. X    if ((fp = ct_popenv(ct, shell, av, "r")) == NULL)
  582. X    {
  583. X        error("can't execute delivery file as %s\n", ct->ct_name);
  584. X        return -1;
  585. X    }
  586. X
  587. X    /*
  588. X     * Read the standard output of the delivery file.
  589. X     */
  590. X
  591. X    while (dfile_gets(fp, &name, &mailbox) >= 0)
  592. X    {
  593. X        DEST    *nd;
  594. X
  595. X        nd = dest(name, mailbox);
  596. X        if (nd->d_state == ST_HOLD)
  597. X            nd->d_state = ST_WORKING;
  598. X
  599. X        /*
  600. X         * If the delivery file specified a mailbox, verify
  601. X         * that the user whose delivery file is running has
  602. X         * permissions for the requested context.
  603. X         */
  604. X
  605. X        if ((nd->d_state == ST_WORKING) && (mailbox != NULL))
  606. X        {
  607. X            CONTEXT *nct;
  608. X
  609. X            if ((nct = name_context(name)) == NULL)
  610. X                dest_err(nd, E_CTLOST);
  611. X            else if (! ok_context(nct))
  612. X                dest_err(nd, E_CTPERM);
  613. X        }
  614. X    }
  615. X
  616. X    return ct_pclose(fp);
  617. X}
  618. X
  619. X/*----------------------------------------------------------------------
  620. X * Get and parse a single delivery file output line.
  621. X */
  622. X
  623. Xint
  624. Xdfile_gets(fp, namep, mailboxp)
  625. XFILE    *fp;
  626. Xchar    **namep;
  627. Xchar    **mailboxp;
  628. X{
  629. X    char    *p, *q;
  630. X    static  char    buf[BUFSIZ];
  631. X
  632. X    if (fgets(buf, GETSIZE(buf), fp) == NULL)
  633. X        return -1;
  634. X
  635. X    if ((p = strchr(buf, '\n')) != NULL)
  636. X        *p = 0;
  637. X    else
  638. X    {
  639. X        int c;
  640. X
  641. X        while ((c = fgetc(fp)) != '\n' && c != EOF)
  642. X            ; /* keep reading */
  643. X
  644. X        error("invalid line from delivery file: '%s'\n", buf);
  645. X        return -1;
  646. X    }
  647. X
  648. X    /* Strip out all whitespace and eliminate duplicated slashes */
  649. X
  650. X    p = q = buf;
  651. X    while (*p)
  652. X    {
  653. X        if (isspace(*p))
  654. X            ++p;
  655. X        else if ((*q++ = *p++) == '/')
  656. X        {
  657. X            while (*p == '/')
  658. X                ++p;
  659. X        }
  660. X    }
  661. X    *q = 0;
  662. X
  663. X    /* Debugging message: display input line */
  664. X
  665. X    if (verbose)
  666. X        message("\t'%s'\n", buf);
  667. X
  668. X    if ((p = strchr(buf, ':')) != NULL)
  669. X    {
  670. X        *p++ = 0;
  671. X        if ((q = strchr(p, ':')) != NULL)
  672. X            *q = 0;
  673. X    }
  674. X
  675. X    *namep = buf;
  676. X    *mailboxp = p;
  677. X    return 0;
  678. X}
  679. X
  680. X/*----------------------------------------------------------------------
  681. X * Make the temp files readable in the given context.
  682. X * This is needed because the temps are readable by owner only.
  683. X */
  684. X
  685. Xint
  686. Xgive_temps(ct)
  687. XCONTEXT *ct;
  688. X{
  689. X    int     err, t;
  690. X
  691. X    if (!ct)
  692. X        return -1;
  693. X
  694. X    err = 0;
  695. X    for (t = T_HDRCOPY; t <= T_BODYCOPY; ++t)
  696. X    {
  697. X        if (chmod(tfile[t], 0600) == -1)
  698. X        {
  699. X            syserr("can't chmod %s", tfile[t]);
  700. X            ++err;
  701. X        }
  702. X        if (chown(tfile[t], ct->ct_uid, ct->ct_gid) == -1)
  703. X        {
  704. X            syserr("can't chown %s to %d/%d",
  705. X                tfile[t], ct->ct_uid, ct->ct_gid);
  706. X            ++err;
  707. X        }
  708. X    }
  709. X
  710. X    return err ? -1 : 0;
  711. X}
  712. END_OF_FILE
  713. if test 8068 -ne `wc -c <'dfile.c'`; then
  714.     echo shar: \"'dfile.c'\" unpacked with wrong size!
  715. fi
  716. # end of 'dfile.c'
  717. fi
  718. if test -f 'lock.c' -a "${1}" != "-c" ; then 
  719.   echo shar: Will not clobber existing file \"'lock.c'\"
  720. else
  721. echo shar: Extracting \"'lock.c'\" \(7155 characters\)
  722. sed "s/^X//" >'lock.c' <<'END_OF_FILE'
  723. X/* $Header: lock.c,v 2.1 89/06/09 12:25:30 network Exp $
  724. X *
  725. X * Mailbox locking.
  726. X * Local hacks for mailbox access should be grafted here.
  727. X *
  728. X * $Log:    lock.c,v $
  729. X * Revision 2.1  89/06/09  12:25:30  network
  730. X * Update RCS revisions.
  731. X * 
  732. X * Revision 1.6  89/06/09  12:23:52  network
  733. X * Baseline for 2.0 release.
  734. X * 
  735. X */
  736. X
  737. X#include "deliver.h"
  738. X
  739. X/*
  740. X * Validate the locking configuration.
  741. X */
  742. X
  743. X#if (defined(ML_FCNTL) + defined(ML_LOCKF) + defined(ML_LOCKING)) > 1
  744. X  lose! "Only one of ML_FCNTL, ML_LOCKF and ML_LOCKING may be defined.";
  745. X#endif
  746. X
  747. X/*
  748. X * Support for the lockf() system call.
  749. X */
  750. X
  751. X#ifdef ML_LOCKF
  752. X#include <unistd.h>
  753. X#define SIMPLE_LOCK "lockf"
  754. X#define LOCKFD(fd, size)    lockf(fd, F_LOCK, size)
  755. X#define UNLOCKFD(fd, size)  lockf(fd, F_ULOCK, size)
  756. X#endif /* ML_LOCKF */
  757. X
  758. X/*
  759. X * Setup for the locking() system call.
  760. X */
  761. X
  762. X#ifdef ML_LOCKING
  763. X#include <sys/locking.h>
  764. X#define SIMPLE_LOCK "locking"
  765. X#define LOCKFD(fd, size)    locking(fd, LK_LOCK, size)
  766. X#define UNLOCKFD(fd, size)  locking(fd, LK_UNLOCK, size)
  767. X#endif
  768. X
  769. X/*
  770. X * Local functions.
  771. X */
  772. X
  773. X#ifdef ML_DOTLOCK
  774. Xstatic  char    *dotlock_name();
  775. X#endif
  776. X#ifdef ML_DOTMLK
  777. Xstatic  char    *dotmlk_name();
  778. X#endif
  779. X
  780. X/*----------------------------------------------------------------------
  781. X * Lock a mailbox by name.
  782. X *
  783. X * This code looks quite hairy with all the ifdefs.  In fact, the only
  784. X * somewhat strange thing here is that neither, either, or both of
  785. X * ML_DOTLOCK and ML_DOTMLK may be defined, and we have to allow for it.
  786. X */
  787. X
  788. Xint
  789. Xname_lock(name)
  790. Xchar    *name;
  791. X{
  792. X#ifdef ML_DOTLOCK
  793. X    char    *dotlock;
  794. X#endif
  795. X#ifdef ML_DOTMLK
  796. X    char    *dotmlk;
  797. X#endif
  798. X
  799. X#ifdef ML_DOTLOCK
  800. X    if ((dotlock = dotlock_name(name)) == NULL
  801. X     || create_lockfile(dotlock) < 0)
  802. X        return -1;
  803. X#endif /* ML_DOTLOCK */
  804. X
  805. X#ifdef ML_DOTMLK
  806. X    if ((dotmlk = dotmlk_name(name)) == NULL
  807. X     || create_lockfile(dotmlk) < 0)
  808. X    {
  809. X#ifdef ML_DOTLOCK
  810. X        (void) remove_lockfile(dotlock); /* don't leave me hanging */
  811. X#endif
  812. X        return -1;
  813. X    }
  814. X#endif /* ML_DOTMLK */
  815. X
  816. X    return 0;
  817. X}
  818. X
  819. X/*----------------------------------------------------------------------
  820. X * Unlock a mailbox by name.
  821. X */
  822. X
  823. Xint
  824. Xname_unlock(name)
  825. Xchar    *name;
  826. X{
  827. X    int     ret = 0;
  828. X
  829. X#ifdef ML_DOTLOCK
  830. X    char    *dotlock;
  831. X#endif
  832. X#ifdef ML_DOTMLK
  833. X    char    *dotmlk;
  834. X#endif
  835. X
  836. X#ifdef ML_DOTLOCK
  837. X    if ((dotlock = dotlock_name(name)) == NULL
  838. X     || remove_lockfile(dotlock) < 0)
  839. X        ret = -1;
  840. X#endif /* ML_DOTLOCK */
  841. X
  842. X#ifdef ML_DOTMLK
  843. X    if ((dotmlk = dotmlk_name(name)) == NULL
  844. X     || remove_lockfile(dotmlk) < 0)
  845. X        ret = -1;
  846. X#endif /* ML_DOTMLK */
  847. X
  848. X    return ret;
  849. X}
  850. X
  851. X/*----------------------------------------------------------------------
  852. X * Lock a file descriptor.
  853. X */
  854. X
  855. Xint
  856. Xfd_lock(fd)
  857. Xint     fd;
  858. X{
  859. X#ifdef ML_FCNTL
  860. X    struct flock fl;
  861. X
  862. X    fl.l_type = F_WRLCK;
  863. X    fl.l_whence = 0;
  864. X    fl.l_start = 0L;
  865. X    fl.l_len = 0L;
  866. X
  867. X    if (fcntl(fd, F_SETLKW, &fl) == -1)
  868. X    {
  869. X        syserr("can't lock with fcntl()");
  870. X        return -1;
  871. X    }
  872. X
  873. X    if (verbose)
  874. X        message("locked mailbox with fcntl()\n");
  875. X#endif /* ML_FCNTL */
  876. X
  877. X#ifdef SIMPLE_LOCK
  878. X    long    pos;
  879. X
  880. X    if ((pos = lseek(fd, 0L, 0)) == -1)
  881. X    {
  882. X        syserr("can't seek in mailbox");
  883. X        return -1;
  884. X    }
  885. X    if (LOCKFD(fd, 0L) == -1)
  886. X    {
  887. X        syserr("can't lock with %s()", SIMPLE_LOCK);
  888. X        return -1;
  889. X    }
  890. X    if (lseek(fd, pos, 0) == -1)
  891. X    {
  892. X        syserr("can't seek in mailbox");
  893. X        return -1;
  894. X    }
  895. X
  896. X    if (verbose)
  897. X        message("locked mailbox with %s()\n", SIMPLE_LOCK);
  898. X#endif /* SIMPLE_LOCK */
  899. X
  900. X    /* Default: success */
  901. X    return 0;
  902. X}
  903. X
  904. X/*----------------------------------------------------------------------
  905. X * Unlock a file descriptor.
  906. X */
  907. X
  908. Xint
  909. Xfd_unlock(fd)
  910. Xint     fd;
  911. X{
  912. X#ifdef ML_FCNTL
  913. X    struct flock fl;
  914. X
  915. X    fl.l_type = F_UNLCK;
  916. X    fl.l_whence = 0;
  917. X    fl.l_start = 0L;
  918. X    fl.l_len = 0L;
  919. X
  920. X    if (fcntl(fd, F_SETLKW, &fl) == -1)
  921. X    {
  922. X        syserr("can't unlock with fcntl()");
  923. X        return -1;
  924. X    }
  925. X
  926. X    if (verbose)
  927. X        message("unlocked mailbox with fcntl()\n");
  928. X#endif /* ML_FCNTL */
  929. X
  930. X#ifdef SIMPLE_LOCK
  931. X    long    pos;
  932. X
  933. X    if ((pos = lseek(fd, 0L, 0)) == -1)
  934. X    {
  935. X        syserr("can't seek in mailbox");
  936. X        return -1;
  937. X    }
  938. X    if (LOCKFD(fd, 0L) == -1)
  939. X    {
  940. X        syserr("can't unlock with %s()", SIMPLE_LOCK);
  941. X        return -1;
  942. X    }
  943. X    if (lseek(fd, pos, 0) == -1)
  944. X    {
  945. X        syserr("can't seek in mailbox");
  946. X        return -1;
  947. X    }
  948. X
  949. X    if (verbose)
  950. X        message("unlocked mailbox with %s()\n", SIMPLE_LOCK);
  951. X#endif /* SIMPLE_LOCK */
  952. X
  953. X    /* Default: success */
  954. X    return 0;
  955. X}
  956. X
  957. X/*----------------------------------------------------------------------
  958. X * Return the name of the appropriate ".lock" file for a mailbox.
  959. X */
  960. X
  961. X#ifdef ML_DOTLOCK
  962. X
  963. Xstatic char *
  964. Xdotlock_name(name)
  965. Xchar    *name;
  966. X{
  967. X    static char *lname = NULL;
  968. X    static int lsize = 0;
  969. X    char    *p;
  970. X    int     n, i;
  971. X
  972. X    n = strlen(name);
  973. X    if (lsize < n + 8)
  974. X    {
  975. X        if (lname)
  976. X            free(lname);
  977. X        lsize = n + 32;
  978. X        lname = zalloc(lsize);
  979. X    }
  980. X
  981. X    (void) strcpy(lname, name);
  982. X
  983. X    /*
  984. X     * We want as much of `basename.lock' as will fit in a string
  985. X     * MAX_NAMESIZE long.
  986. X     */
  987. X    for (i = 0, p = basename(lname); (i < MAX_NAMESIZE - 5) && (*p); ++i)
  988. X        ++p;
  989. X    (void) strcpy(p, ".lock");
  990. X
  991. X    return lname;
  992. X}
  993. X
  994. X#endif /* ML_DOTLOCK */
  995. X
  996. X/*----------------------------------------------------------------------
  997. X * Return the name of the appropriate ".mlk" file for a mailbox.
  998. X */
  999. X
  1000. X#ifdef ML_DOTMLK
  1001. X
  1002. Xstatic char *
  1003. Xdotmlk_name(name)
  1004. Xchar    *name;
  1005. X{
  1006. X    static char lname[MAX_NAMESIZE + 16];
  1007. X    char    *p, *d;
  1008. X    int     i;
  1009. X
  1010. X    /*
  1011. X     * To explain the below:  If we ass_u_me that MAX_NAMESIZE is 14,
  1012. X     * then this code is like `printf(lname, "/tmp/%.10s.mlk", ...)'.
  1013. X     * In other words, we want as much of `basename.mlk' as will fit
  1014. X     * in a string MAX_NAMESIZE long.
  1015. X     */
  1016. X    d = lname;
  1017. X    for (p = "/tmp/"; *p; )
  1018. X        *d++ = *p++;
  1019. X    for (i = 0, p = basename(name); (i < MAX_NAMESIZE - 4) && (*p); ++i)
  1020. X        *d++ = *p++;
  1021. X    (void) strcpy(d, ".mlk");
  1022. X
  1023. X    return lname;
  1024. X}
  1025. X
  1026. X#endif /* ML_DOTMLK */
  1027. X
  1028. X/*----------------------------------------------------------------------
  1029. X * Create a lockfile.
  1030. X */
  1031. X
  1032. Xint
  1033. Xcreate_lockfile(name)
  1034. Xchar    *name;
  1035. X{
  1036. X#ifndef O_CREAT
  1037. X    char    *othername, *p;
  1038. X#endif
  1039. X    int     fd, tries;
  1040. X
  1041. X#ifndef O_CREAT
  1042. X    othername = zalloc(strlen(name) + 20);  /* fudge (???) */
  1043. X    (void) strcpy(othername, name);
  1044. X    (void) sprintf(basename(othername), ".dl.%d", getpid());
  1045. X    if ((fd = creat(othername, 0)) == -1)
  1046. X    {
  1047. X        syserr("can't create %s", othername);
  1048. X        return -1;
  1049. X    }
  1050. X    (void) close(fd);
  1051. X    if (verbose)
  1052. X        message("created pre-lockfile %s\n", name);
  1053. X#endif
  1054. X
  1055. X    for (tries = 0; tries < 10; ++tries)
  1056. X    {
  1057. X        if (tries)
  1058. X            snooze(3);
  1059. X
  1060. X#ifdef O_CREAT
  1061. X
  1062. X        if ((fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0)) >= 0)
  1063. X        {
  1064. X            (void) close(fd);
  1065. X            if (verbose)
  1066. X                message("created lockfile %s\n", name);
  1067. X            return 0;
  1068. X        }
  1069. X
  1070. X#else /* not O_CREAT */
  1071. X
  1072. X        if (link(othername, name) == 0)
  1073. X        {
  1074. X            if (unlink(othername) == -1)
  1075. X                syserr("can't remove %s", othername);
  1076. X            free(othername);
  1077. X            if (verbose)
  1078. X                message("created lockfile %s\n", name);
  1079. X            return 0;
  1080. X        }
  1081. X
  1082. X#endif /* not O_CREAT */
  1083. X
  1084. X        if (verbose && (tries == 0))
  1085. X            message("Waiting to create %s\n", name);
  1086. X    }
  1087. X
  1088. X    syserr("can't create lockfile %s", name);
  1089. X    return -1;
  1090. X}
  1091. X
  1092. X/*----------------------------------------------------------------------
  1093. X * Remove a lockfile.
  1094. X */
  1095. X
  1096. Xint
  1097. Xremove_lockfile(name)
  1098. Xchar    *name;
  1099. X{
  1100. X    if (unlink(name) == -1)
  1101. X    {
  1102. X        syserr("can't remove lockfile %s", name);
  1103. X        return -1;
  1104. X    }
  1105. X
  1106. X    if (verbose)
  1107. X        message("removed lockfile %s\n", name);
  1108. X
  1109. X    return 0;
  1110. X}
  1111. END_OF_FILE
  1112. if test 7155 -ne `wc -c <'lock.c'`; then
  1113.     echo shar: \"'lock.c'\" unpacked with wrong size!
  1114. fi
  1115. # end of 'lock.c'
  1116. fi
  1117. if test -f 'main.c' -a "${1}" != "-c" ; then 
  1118.   echo shar: Will not clobber existing file \"'main.c'\"
  1119. else
  1120. echo shar: Extracting \"'main.c'\" \(12025 characters\)
  1121. sed "s/^X//" >'main.c' <<'END_OF_FILE'
  1122. X/* $Header: main.c,v 2.1 89/06/09 12:25:32 network Exp $
  1123. X *
  1124. X * A program to deliver local mail with some flexibility.
  1125. X *
  1126. X * $Log:    main.c,v $
  1127. X * Revision 2.1  89/06/09  12:25:32  network
  1128. X * Update RCS revisions.
  1129. X * 
  1130. X * Revision 1.13  89/06/09  12:23:53  network
  1131. X * Baseline for 2.0 release.
  1132. X * 
  1133. X */
  1134. X
  1135. X#include "deliver.h"
  1136. X#include "patchlevel.h"
  1137. X#include <signal.h>
  1138. X
  1139. X/*
  1140. X * External data.
  1141. X */
  1142. X
  1143. X/* Variables set by getopt() [blech] */
  1144. X
  1145. Xextern  int     optind, opterr;
  1146. Xextern  char    *optarg;
  1147. X
  1148. X/*
  1149. X * Local data
  1150. X */
  1151. X
  1152. Xstatic  char    sys_dfl[] = SYS_DELIVER;
  1153. Xstatic  char    post_dfl[] = POST_DELIVER;
  1154. Xstatic  char    user_dfl[] = USER_DELIVER;
  1155. X
  1156. X/*
  1157. X * Global data
  1158. X */
  1159. X
  1160. Xint     verbose         = FALSE;
  1161. Xint     dryrun          = FALSE;
  1162. Xint     rundfiles       = TRUE;
  1163. Xint     printaddrs      = FALSE;
  1164. Xint     leavetemps      = FALSE;
  1165. Xint     boxdelivery     = FALSE;
  1166. X
  1167. Xchar    *progname       = "deliver";
  1168. Xchar    version[32]     = "2.0";
  1169. Xchar    *shell          = SHELL;
  1170. X
  1171. Xchar    *sys_deliver    = sys_dfl;
  1172. Xchar    *post_deliver   = post_dfl;
  1173. Xchar    *user_deliver   = user_dfl;
  1174. Xchar    *sender         = NULL;
  1175. Xchar    *hostname       = NULL;
  1176. X
  1177. Xint     eff_uid         = -1;
  1178. Xint     eff_gid         = -1;
  1179. Xint     real_uid        = -1;
  1180. Xint     real_gid        = -1;
  1181. X
  1182. XCONTEXT *eff_ct         = NULL;
  1183. XCONTEXT *real_ct        = NULL;
  1184. X
  1185. Xint     tty_input       = FALSE;
  1186. XSIGFLAG got_sig         = FALSE;
  1187. X
  1188. Xint     trust_user      = FALSE;
  1189. Xint     trust_delfiles  = FALSE;
  1190. X
  1191. Xchar    *ttype[T_MAX]   = { "header", "body", "header copy", "body copy" };
  1192. Xchar    *tfile[T_MAX]   = { NULL, NULL, NULL, NULL };
  1193. Xchar    *tenv[T_MAX]    = { NULL, NULL, ENV_HEADER, ENV_BODY };
  1194. Xint     tfd[T_MAX]      = { -1, -1, -1, -1 };
  1195. X
  1196. X/*
  1197. X * Local functions.
  1198. X */
  1199. X
  1200. Xstatic  SIGTYPE sighup(), sigint(), sigquit();
  1201. X
  1202. X/*----------------------------------------------------------------------
  1203. X * The Program.
  1204. X */
  1205. X
  1206. Xmain(argc, argv)
  1207. Xint     argc;
  1208. Xchar    **argv;
  1209. X{
  1210. X    char    *p;
  1211. X    int     u, c, errcount, copy;
  1212. X
  1213. X    /* Make sure that stdout and stderr are interleaved correctly */
  1214. X
  1215. X    Linebuf(stdout);
  1216. X    Linebuf(stderr);
  1217. X
  1218. X    /* Figure out the name used to invoke this program. */
  1219. X
  1220. X    progname = basename(argv[0]);
  1221. X
  1222. X    /* What version of the program is this? */
  1223. X
  1224. X    (void) sprintf(version + strlen(version), ".%02d", PATCHLEVEL);
  1225. X
  1226. X    /* Figure out the name of this host */
  1227. X
  1228. X    if ((hostname = gethost()) == NULL)
  1229. X    {
  1230. X        hostname = "unknown";
  1231. X        error("unable to determine host name; using \"%s\"\n",
  1232. X              hostname);
  1233. X    }
  1234. X
  1235. X    /* Find effective and real uids and gids. */
  1236. X
  1237. X    eff_uid = geteuid();
  1238. X    eff_gid = getegid();
  1239. X    real_uid = getuid();
  1240. X    real_gid = getgid();
  1241. X
  1242. X    if (eff_uid != real_uid && eff_uid != 0)
  1243. X    {
  1244. X        error("if setuid, must be setuid root\n");
  1245. X        leave(1);
  1246. X    }
  1247. X
  1248. X    /* Process environment: handle recursive invocation */
  1249. X
  1250. X    if ((p = getenv(ENV_DFLAGS)) != NULL)
  1251. X    {
  1252. X        while (*p)
  1253. X        {
  1254. X            switch (*p++)
  1255. X            {
  1256. X            case 'v':
  1257. X                verbose = TRUE;
  1258. X                break;
  1259. X            case 'd':
  1260. X                verbose = TRUE;
  1261. X                dryrun = TRUE;
  1262. X                break;
  1263. X            case 'A':
  1264. X                printaddrs = TRUE;
  1265. X                dryrun = TRUE;
  1266. X                break;
  1267. X            case 'n':
  1268. X                rundfiles = FALSE;
  1269. X                break;
  1270. X            case 't':
  1271. X                leavetemps = TRUE;
  1272. X                break;
  1273. X            }
  1274. X        }
  1275. X    }
  1276. X
  1277. X    if ((p = getenv(ENV_SYSDEL)) != NULL && *p)
  1278. X        sys_deliver = p;
  1279. X    if ((p = getenv(ENV_POSTDEL)) != NULL && *p)
  1280. X        post_deliver = p;
  1281. X    if ((p = getenv(ENV_USERDEL)) != NULL && *p)
  1282. X        user_deliver = p;
  1283. X    if ((p = getenv(ENV_SENDER)) != NULL && *p)
  1284. X        sender = p;
  1285. X    if ((p = getenv(ENV_HOSTNAME)) != NULL && *p)
  1286. X        hostname = p;
  1287. X
  1288. X    /* Parse command line arguments */
  1289. X
  1290. X    while ((c = getopt(argc, argv, "vdAntbs:p:u:r:h:")) != EOF)
  1291. X    {
  1292. X        switch (c)
  1293. X        {
  1294. X        case 'v':
  1295. X            verbose = TRUE;
  1296. X            break;
  1297. X        case 'd':
  1298. X            verbose = TRUE;
  1299. X            dryrun = TRUE;
  1300. X            break;
  1301. X        case 'A':
  1302. X            printaddrs = TRUE;
  1303. X            dryrun = TRUE;
  1304. X            break;
  1305. X        case 'n':
  1306. X            rundfiles = FALSE;
  1307. X            break;
  1308. X        case 't':
  1309. X            leavetemps = TRUE;
  1310. X            break;
  1311. X        case 'b':
  1312. X            boxdelivery = TRUE;
  1313. X            break;
  1314. X        case 's':
  1315. X            if (*optarg)
  1316. X                sys_deliver = optarg;
  1317. X            break;
  1318. X        case 'p':
  1319. X            if (*optarg)
  1320. X                post_deliver = optarg;
  1321. X            break;
  1322. X        case 'u':
  1323. X            if (*optarg)
  1324. X                user_deliver = optarg;
  1325. X            break;
  1326. X        case 'r':
  1327. X            if (*optarg)
  1328. X                sender = optarg;
  1329. X            break;
  1330. X        case 'h':
  1331. X            if (*optarg)
  1332. X                hostname = optarg;
  1333. X            break;
  1334. X        case '?':
  1335. X            usage();
  1336. X        }
  1337. X    }
  1338. X
  1339. X    /* If no destinations were given, forget it. */
  1340. X
  1341. X    if (optind >= argc)
  1342. X    {
  1343. X        error("no recipients specified\n");
  1344. X        usage();
  1345. X    }
  1346. X
  1347. X    /* Print a debugging message */
  1348. X
  1349. X    if (verbose)
  1350. X    {
  1351. X        message("%s %s running on host %s\n",
  1352. X            progname, version, hostname);
  1353. X    }
  1354. X
  1355. X    /* Do we trust our caller? */
  1356. X
  1357. X    if (trusted_uid(real_uid))
  1358. X        trust_user = TRUE;
  1359. X
  1360. X    /* Do we trust our delivery files? */
  1361. X
  1362. X    if (strcmp(sys_dfl, sys_deliver) == 0
  1363. X     && strcmp(post_dfl, post_deliver) == 0
  1364. X     && strcmp(user_dfl, user_deliver) == 0)
  1365. X        trust_delfiles = TRUE;
  1366. X
  1367. X    /* Renounce special privileges if something insecure was requested. */
  1368. X
  1369. X    if (!trust_user && !trust_delfiles)
  1370. X    {
  1371. X        if (setgid(eff_gid = real_gid) == -1
  1372. X         || setuid(eff_uid = real_uid) == -1)
  1373. X        {
  1374. X            syserr("can't renounce setuid privileges");
  1375. X            leave(1);
  1376. X        }
  1377. X    }
  1378. X
  1379. X    /* Get the contexts of our effective and real uids. */
  1380. X
  1381. X    if ((eff_ct = uid_context(eff_uid)) == NULL)
  1382. X        error("invalid effective uid %d!?\n", eff_uid);
  1383. X
  1384. X    if ((real_ct = uid_context(real_uid)) == NULL)
  1385. X        error("invalid real uid %d!?\n", real_uid);
  1386. X
  1387. X    if (!eff_ct || !real_ct)
  1388. X        leave(1);
  1389. X
  1390. X    if (verbose)
  1391. X    {
  1392. X        message("effective uid = %s (%d/%d); real uid = %s (%d/%d)\n",
  1393. X            eff_ct->ct_name, eff_ct->ct_uid, eff_ct->ct_gid,
  1394. X            real_ct->ct_name, real_ct->ct_uid, real_ct->ct_gid);
  1395. X    }
  1396. X
  1397. X    /* Let's be sane about the file creation mask. */
  1398. X
  1399. X    u = umask(0);
  1400. X    u &= ~0700;     /* Let's not deprive ourselves of permissions.  */
  1401. X    u |= 022;       /* Let's be reasonably paranoid about writing.  */
  1402. X    (void) umask(u);
  1403. X
  1404. X    /*
  1405. X     * Where is the message coming from?
  1406. X     */
  1407. X
  1408. X    if (isatty(0))
  1409. X        tty_input = TRUE;
  1410. X
  1411. X    /*
  1412. X     * If we are not going to deliver, or if we are receiving the
  1413. X     * message from a tty, catch signals so we can remove temp files.
  1414. X     * Otherwise, ignore signals.
  1415. X     */
  1416. X
  1417. X    if (dryrun || tty_input)
  1418. X        catch_sigs();
  1419. X    else
  1420. X        ignore_sigs();
  1421. X
  1422. X    /*
  1423. X     * Create the temporary files and write the message to them.
  1424. X     */
  1425. X
  1426. X    copy = copy_message();
  1427. X
  1428. X    /*
  1429. X     * No more signals...
  1430. X     */
  1431. X
  1432. X    ignore_sigs();
  1433. X
  1434. X    /*
  1435. X     * ... but if we had already caught a signal,
  1436. X     *     or if copy_msg() had a problem, leave.
  1437. X     */
  1438. X
  1439. X    if ((copy < 0) || got_sig)
  1440. X    {
  1441. X        if (got_sig)
  1442. X            error("caught signal - exiting\n");
  1443. X        leave(1);
  1444. X    }
  1445. X
  1446. X    /*
  1447. X     * Set up useful environment variables.
  1448. X     * Note that this must be done _after_ copy_message(),
  1449. X     * since that's where the temp files are created.
  1450. X     */
  1451. X
  1452. X    setup_environ();
  1453. X
  1454. X    /*
  1455. X     * Perhaps we should consider all arguments as mailbox names...
  1456. X     */
  1457. X
  1458. X    if (boxdelivery)
  1459. X    {
  1460. X        int     a;
  1461. X
  1462. X        if (verbose)
  1463. X            message("mailbox delivery as %s\n", real_ct->ct_name);
  1464. X
  1465. X        /*
  1466. X         * Consider all arguments as mailbox filenames.
  1467. X         */
  1468. X
  1469. X        for (a = optind; a < argc; ++a)
  1470. X            (void) dest(real_ct->ct_name, argv[a]);
  1471. X
  1472. X        if (verbose)
  1473. X            dumpdests("(should all be mailboxes)");
  1474. X    }
  1475. X
  1476. X    /*
  1477. X     * They're not mailbox names, so they should be mail addresses.
  1478. X     */
  1479. X
  1480. X    else
  1481. X    {
  1482. X        /* Run all destinations though the system delivery file. */
  1483. X
  1484. X        if (sys_dfile(argc - optind, argv + optind) >= 0)
  1485. X        {
  1486. X            if (verbose)
  1487. X                dumpdests("after running system delivery file");
  1488. X        }
  1489. X        else
  1490. X        {
  1491. X            int     a;
  1492. X
  1493. X            /*
  1494. X             * System delivery file is missing or ignored.
  1495. X             * Use the argument list verbatim.
  1496. X             */
  1497. X
  1498. X            for (a = optind; a < argc; ++a)
  1499. X                (void) dest(argv[a], (char *) NULL);
  1500. X
  1501. X            if (verbose)
  1502. X                dumpdests("as taken from argument list");
  1503. X        }
  1504. X
  1505. X        /*
  1506. X         * Run each user destination through his delivery file.
  1507. X         */
  1508. X
  1509. X        if (user_dfiles() >= 0)
  1510. X        {
  1511. X            if (verbose)
  1512. X                dumpdests("after running user delivery files");
  1513. X        }
  1514. X
  1515. X        /*
  1516. X         * Run each remaining destination though the post-user
  1517. X         * delivery file.
  1518. X         */
  1519. X
  1520. X        if (post_dfile() >= 0)
  1521. X        {
  1522. X            if (verbose)
  1523. X                dumpdests("after running post-user delivery file");
  1524. X        }
  1525. X    }
  1526. X
  1527. X    /*
  1528. X     * Drop mail in mailbox(es).
  1529. X     */
  1530. X
  1531. X    mbox_deliver();
  1532. X
  1533. X    if (verbose)
  1534. X        dumpdests("after delivery to all mailboxes");
  1535. X
  1536. X    /*
  1537. X     * Send mail to UUCP address(es).
  1538. X     */
  1539. X
  1540. X    uucp_deliver();
  1541. X
  1542. X    if (verbose)
  1543. X        dumpdests("after delivery to UUCP addresses");
  1544. X
  1545. X    /*
  1546. X     * Report any errors, and leave.
  1547. X     */
  1548. X
  1549. X    errcount = report_errors();
  1550. X
  1551. X    /*
  1552. X     * All done.
  1553. X     */
  1554. X
  1555. X    leave(errcount ? 1 : 0);
  1556. X    /* NOTREACHED */
  1557. X}
  1558. X
  1559. X/*----------------------------------------------------------------------
  1560. X * Print a usage message and exit.
  1561. X */
  1562. X
  1563. Xusage()
  1564. X{
  1565. X    message("Usage: %s [-b][-A][-d][-v][-n][-t][-r from][-h host] args\n", progname);
  1566. X    message("-b       All arguments are mailbox filenames.\n");
  1567. X    message("         (Default: arguments are user names.)\n");
  1568. X    message("-A       Resolve addresses but do not deliver.\n");
  1569. X    message("-d       Be verbose but do not deliver.\n");
  1570. X    message("-v       Be verbose and deliver.\n");
  1571. X    message("-n       Do not run any delivery files.\n");
  1572. X    message("-t       Do not remote temp files before exiting.\n");
  1573. X    message("-s file  Specify the system delivery filename.\n");
  1574. X    message("-p file  Specify the post-user delivery filename.\n");
  1575. X    message("-u file  Specify the user delivery filename.\n");
  1576. X    message("-r from  Specify the address to appear in the \"From \" line.\n");
  1577. X    message("-h host  Specify the host name.\n");
  1578. X    message("args     Either user addresses or mailboxes (-b).\n");
  1579. X    leave(1);
  1580. X}
  1581. X
  1582. X/*----------------------------------------------------------------------
  1583. X * Clean up and exit.
  1584. X */
  1585. X
  1586. Xleave(code)
  1587. Xint     code;
  1588. X{
  1589. X    if (! leavetemps)
  1590. X    {
  1591. X        int     t;
  1592. X
  1593. X        for (t = 0; t < T_MAX; ++t)
  1594. X        {
  1595. X            if (tfd[t] != -1)
  1596. X                (void) close(tfd[t]);
  1597. X            if (tfile[t] && unlink(tfile[t]) == -1)
  1598. X                syserr("can't unlink %s", tfile[t]);
  1599. X        }
  1600. X    }
  1601. X
  1602. X    exit(code);
  1603. X}
  1604. X
  1605. X/*----------------------------------------------------------------------
  1606. X * Catch signals.
  1607. X */
  1608. X
  1609. Xcatch_sigs()
  1610. X{
  1611. X    if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
  1612. X        (void) signal(SIGHUP, sighup);
  1613. X    if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  1614. X        (void) signal(SIGINT, sigint);
  1615. X    if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
  1616. X        (void) signal(SIGQUIT, sigquit);
  1617. X}
  1618. X
  1619. X/*----------------------------------------------------------------------
  1620. X * Ignore signals.
  1621. X */
  1622. X
  1623. Xignore_sigs()
  1624. X{
  1625. X    (void) signal(SIGHUP, SIG_IGN);
  1626. X    (void) signal(SIGINT, SIG_IGN);
  1627. X    (void) signal(SIGQUIT, SIG_IGN);
  1628. X}
  1629. X
  1630. Xstatic SIGTYPE
  1631. Xsighup()
  1632. X{
  1633. X    (void) signal(SIGHUP, sighup);
  1634. X    got_sig = TRUE;
  1635. X}
  1636. X
  1637. Xstatic SIGTYPE
  1638. Xsigint()
  1639. X{
  1640. X    (void) signal(SIGINT, sigint);
  1641. X    got_sig = TRUE;
  1642. X}
  1643. X
  1644. Xstatic SIGTYPE
  1645. Xsigquit()
  1646. X{
  1647. X    (void) signal(SIGQUIT, sigquit);
  1648. X    got_sig = TRUE;
  1649. X}
  1650. X
  1651. X/*----------------------------------------------------------------------
  1652. X * Report any errors to stderr.
  1653. X * Return an error count.
  1654. X */
  1655. X
  1656. Xint
  1657. Xreport_errors()
  1658. X{
  1659. X    DEST    *d;
  1660. X    int     count = 0;
  1661. X
  1662. X    for (d = first_dest(); d; d = next_dest(d))
  1663. X    {
  1664. X        if (d->d_state != ST_ERROR)
  1665. X            continue;
  1666. X
  1667. X        if (++count == 1)
  1668. X        {
  1669. X            error(
  1670. X            "delivery to the following address(es) failed on host %s\n",
  1671. X                hostname);
  1672. X        }
  1673. X
  1674. X        message("\t\"%s\"", d->d_name);
  1675. X        if (d->d_class == CL_MBOX)
  1676. X            message(", mailbox \"%s\"", d->d_mailbox);
  1677. X        message(": %s\n", derrmsg(d->d_error));
  1678. X    }
  1679. X
  1680. X    return count;
  1681. X}
  1682. X
  1683. X/*----------------------------------------------------------------------
  1684. X * Is the given uid trusted?
  1685. X */
  1686. X
  1687. Xint
  1688. Xtrusted_uid(uid)
  1689. Xint     uid;
  1690. X{
  1691. X    CONTEXT *ct;
  1692. X    char    **n;
  1693. X    static char *t[] = { TRUSTED_USERS, 0 };
  1694. X
  1695. X    for (n = t; *n; ++n)
  1696. X    {
  1697. X        if ((ct = name_context(*n)) != NULL && uid == ct->ct_uid)
  1698. X            return TRUE;
  1699. X    }
  1700. X
  1701. X    return FALSE;
  1702. X}
  1703. X
  1704. X/*----------------------------------------------------------------------
  1705. X * Set up useful environment variables.
  1706. X */
  1707. X
  1708. Xsetup_environ()
  1709. X{
  1710. X    char    flags[8];
  1711. X    int     f = 0;
  1712. X
  1713. X    flags[f++] = '-';
  1714. X    if (verbose)
  1715. X        flags[f++] = (dryrun ? 'd' : 'v');
  1716. X    if (printaddrs)
  1717. X        flags[f++] = 'A';
  1718. X    if (leavetemps)
  1719. X        flags[f++] = 't';
  1720. X    flags[f] = 0;
  1721. X
  1722. X    alloc_env(ENV_DFLAGS, (f > 1) ? flags : "");
  1723. X    if (sys_deliver && *sys_deliver)
  1724. X        alloc_env(ENV_SYSDEL, sys_deliver);
  1725. X    if (user_deliver && *user_deliver)
  1726. X        alloc_env(ENV_USERDEL, user_deliver);
  1727. X    if (hostname && *hostname)
  1728. X        alloc_env(ENV_HOSTNAME, hostname);
  1729. X    if (sender && *sender)
  1730. X        alloc_env(ENV_SENDER, sender);
  1731. X
  1732. X    alloc_env("IFS", " \t\n");
  1733. X    del_env("ENV");         /* in case SHELL is ksh */
  1734. X}
  1735. END_OF_FILE
  1736. if test 12025 -ne `wc -c <'main.c'`; then
  1737.     echo shar: \"'main.c'\" unpacked with wrong size!
  1738. fi
  1739. # end of 'main.c'
  1740. fi
  1741. echo shar: End of shell archive.
  1742. exit 0
  1743.  
  1744.  
  1745.